import os
import sys
import logging

from command_parser.command_parser_container import CmdParserContainer
from command_parser.option_parser import *
from utils.common_utils import *
from command_parser.ld_parse.ld_command_generator import LDGenCommand
from command_parser.ld_parse.ld_option_dict import *

class LDParser(CmdParserContainer):
    def __init__(self, command=[], context=None, linker="", options=[], cwd=""):
        self.command = command
        self.context = context
        self.linker = linker
        self.options = options
        self.cwd = cwd
        self.cmd_gen = LDGenCommand(context=context, cwd=self.cwd)
        self.option_dict = None
        
    def parse_command(self, command=[]):
        
        if not command:
            command = self.command
        
        self.linker = command[0]
        argv = command[1:]
        self.option_dict = OptionDict(option_dict_xml)
        self.options = self.build_options(parse_at_option(argv))
        self.linker = real_binary_path(self.linker)
        return self.linker, self.options
        
        
    def build_options(self, raw_options=[]):
        options = []
        i = 0
        while i < len(raw_options):
            raw_opt = raw_options[i]
            if raw_opt[0] != '-':  
                option = Option('', [raw_opt], PREFIX_MATCH, OptionCategory.OBJECT_FILE)
            else:
                option = get_simple_option(option=raw_opt, option_dict=self.option_dict.get_simple_dict())         
                if not option:
                    option = get_space_option(prefix=raw_opt, params=raw_options[i+1] if i+1 < len(raw_options) else '', option_dict=self.option_dict.get_space_dict())
                    if option:
                        i += 1
                    else:
                        option = get_equal_option(option=raw_opt, option_dict=self.option_dict.get_equal_dict())
                        if not option:
                            option = get_match_option(option=raw_opt, option_dict=self.option_dict.get_match_dict())
                            if not option:
                                option = get_unknown_option(option=raw_opt, next_opt=raw_options[i+1] if i+1 < len(raw_options) else '', OptionCategory=OptionCategory)
                                if option.type == PREFIX_SPACE:
                                    i += 1
                                logging.warning("unknown ld option" + str(vars(option)))
            i += 1
            options.append(option)
        return options
    
    def get_input_options(self):
        
        base_inputs = [item for item in self.options if not item.option]
        
        return base_inputs
    
    def get_output_options(self):
        
        base_output = []
        for index in range(len(self.options) - 1, -1, -1):
            # For '-o' option, the last is valid.
            if self.options[index].option == '-o':
                base_output.append(self.options[index])
                break
        
        return base_output
    
    def auto_check_output_options(self):
        output = self.get_output_options()
        if not output:
            output = self.generate_temporary_target()
            self.extend_options_by_list([output])
    
    
    def generate_temporary_target(self):
        
        out_opt = Option(option='-o', parameter=['a.out'], type=PREFIX_SPACE)
        return out_opt

    def get_original_command(self):
        return self.cmd_gen.generate_original_command(compiler=self.linker, options=self.options)
    
    def get_maple_link_command(self):
        input_opts = self.get_input_options()
        output_opt = self.get_output_options()[0]
        
        return self.cmd_gen.generate_maple_link_command(compiler=self.context.MAPLE_BIN, input_options=input_opts, output_option=output_opt)